using System.Configuration;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
using System.Data;
using System;
using System.Collections;
using Microsoft.SharePoint;
using System.Diagnostics;

namespace MultiLevelSelectField
{

    // custom field type uses helper class to initialize and render control
    public class MultiLevelSelectFieldControl : BaseFieldControl
    {
        protected TreeView TreeView1;

        public override string DisplayTemplateName
        {
            get { return @"MacawMastWss3TemplatesMultiLevelSelectControlDisplay"; }
        }

        protected override string DefaultTemplateName
        {
            get { return @"MacawMastWss3TemplatesMultiLevelSelectControl"; }
        }

        /// <summary>
        /// This method loops through all childnodes to find the node with the specified value
        /// </summary>
        /// <param name="treeview"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private TreeNode FindNode(TreeView treeview, string value)
        {
            foreach (TreeNode node in treeview.Nodes)
            {
                if (node.Value == value) return node;
                TreeNode result = FindNode(node, value);
                if (result != null) return result;
            }
            return null;
        }

        /// <summary>
        /// This method recurses all the childnodes to find the node with the specified value
        /// </summary>
        /// <param name="node"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private TreeNode FindNode(TreeNode node, string value)
        {
            if (node.Value == value) return node;

            foreach (TreeNode n in node.ChildNodes)
            {
                TreeNode result = FindNode(n, value);
                if (result != null) return result;
            }

            return null;
        }

        public override object Value
        {
            get
            {
                // Get the value from the control so it can be stored in the listitem
                EnsureChildControls();
                MultiLevelSelectFieldValue mlsfv = new MultiLevelSelectFieldValue();
                foreach (TreeNode node in TreeView1.CheckedNodes)
                {
                    mlsfv.Items.Add(new MultiLevelSelectFieldValueItem(node.Value));
                }

                return mlsfv;
            }
            set
            {
                // Set the value to the control by the value which was stored in the listitem
                EnsureChildControls();
                MultiLevelSelectFieldValue mlsfv = (MultiLevelSelectFieldValue)value;
                foreach (MultiLevelSelectFieldValueItem item in mlsfv.Items)
                {
                    TreeNode foundnode = FindNode( TreeView1, item.Url);
                    if (foundnode != null)
                    {
                        foundnode.Checked = true;
                    }
                }

            }
        }

        private void ProcessList(string listurl)
        {
            SPFieldLookup sfl = null;
            using (SPWeb web = SPContext.Current.Site.OpenWeb(listurl))
            {
                SPList list = web.GetList(listurl);

                // Find lookup-field to parent
                foreach (SPField field in list.Fields)
                {
                    if (field is SPFieldLookup && !field.FromBaseType)
                    {
                        if (sfl != null) throw new Exception("To have multiple lookupfields is not supported");
                        sfl = (SPFieldLookup)field;
                    }
                }

                // Recurse into parent list
                if (sfl != null)
                {
                    using (SPWeb web2 = SPContext.Current.Site.OpenWeb(sfl.LookupWebId))
                    {
                        Guid listguid = Guid.Empty;
                        try
                        {
                            listguid = new Guid(sfl.LookupList);
                        }
                        catch
                        { }

                        SPList list2 = null;
                        try
                        {
                            if (!listguid.Equals(Guid.Empty))
                            {
                                list2 = web2.Lists[listguid];
                            }
                            else list2 = web2.Lists[sfl.LookupList];
                        }
                        catch (ArgumentException)
                        {
                            SPSecurity.RunWithElevatedPrivileges(delegate
                            {
                                EventLog.WriteEntry(this.GetType().FullName, string.Format("Unable to retrieve list '{0}'", sfl.LookupList), EventLogEntryType.Error);
                            }
                            );
                            throw;
                        }

                        ProcessList(list2.DefaultViewUrl);

                        // Add all items to the treeview
                        foreach (SPListItem item in list.Items)
                        {
                            TreeNode node = new TreeNode(item.Title, item.Url);
                            SPFieldLookupValue fluv = new SPFieldLookupValue((string)item[sfl.Id]);
                            SPListItem item2 = list2.GetItemById(fluv.LookupId);
                            TreeNode parentnode = FindNode( TreeView1 , item2.Url);
                            if (parentnode == null)
                            {
                                throw new Exception(string.Format("Unable to find parentnode with value \"{0}\"" , fluv.LookupValue));
                            }
                            node.SelectAction = TreeNodeSelectAction.None;
                            node.PopulateOnDemand = false;
                            parentnode.ChildNodes.Add(node);
                        }
                    }
                }
                else
                {
                    // Add all items to the treeview
                    foreach (SPListItem item in list.Items)
                    {
                        TreeNode node = new TreeNode(item.Title, item.Url);
                        node.SelectAction = TreeNodeSelectAction.None;
                        node.PopulateOnDemand = false;
                        TreeView1.Nodes.Add(node);
                    }
                }
            }
        }

        protected override void CreateChildControls()
        {
            if (Field == null)
            {
                return;
            }

            base.CreateChildControls();

            TreeView1 = (TreeView)TemplateContainer.FindControl("TreeView1");

            if (TreeView1 == null)
            {
                throw new Exception("Corrupted MultiLevelSelectControl.ascx file.");
            }


            if (!Page.IsPostBack)
            {
                MultiLevelSelectField mlsf = (MultiLevelSelectField)this.Field;
                TreeView1.Nodes.Clear();
                ProcessList(mlsf.ListUrl);
            }

            if (ControlMode == SPControlMode.Display && ItemFieldValue!=null)
            {
                MultiLevelSelectFieldValue mlsfv = (MultiLevelSelectFieldValue)ItemFieldValue;
                foreach (MultiLevelSelectFieldValueItem item in mlsfv.Items)
                {
                    TreeNode foundnode = FindNode( TreeView1, item.Url);
                    if (foundnode != null)
                    {
                        foundnode.Checked = true;
                    }
                    else
                    {
                        //throw new Exception(string.Format("Node \"{0}\" not found", item.Url));
                    }
                }
            }
            else
            {
                System.Web.UI.WebControls.Literal l = new Literal();
                l.Text = "<script language=javascript>" +
                         "Update('" + TreeView1.ClientID + "');" +
                         "</script>";
                this.Controls.Add(l);
            }
        }
    }
}
